package com.gitee.wsl.time

import kotlinx.datetime.DayOfWeek
import kotlinx.datetime.isoDayNumber
import kotlin.jvm.JvmOverloads

/**
 * Number of days in a wekk.
 */
const val DayOfWeekCount: Int = 7

/**
 * Returns the days of week values such that the desired
 * [firstDayOfWeek] property is at the start position.
 *
 * @see [firstDayOfWeekBySystem]
 */
@JvmOverloads
fun daysOfWeek(firstDayOfWeek: DayOfWeek = firstDayOfWeekBySystem()): List<DayOfWeek> {
    val pivot = 7 - firstDayOfWeek.ordinal
    val daysOfWeek = DayOfWeek.entries
    // Order `daysOfWeek` array so that firstDayOfWeek is at the start position.
    return daysOfWeek.takeLast(pivot) + daysOfWeek.dropLast(pivot)
}

/**
 *  ISO8601 value of the day of the week, from 1 (Monday) to 7 (Sunday).
 */
//val DayOfWeek.value: Int get() = ordinal + 1

expect fun DayOfWeek.localizedBySystem(): String

/**
 * Returns the first day of the week from the provided locale.
 */
expect fun firstDayOfWeekBySystem(): DayOfWeek

fun daysOfWeekSortedBy(
    firstDayOfWeek: DayOfWeek = firstDayOfWeekBySystem()
) = DayOfWeek.entries.toTypedArray().let {
    val n = it.size - firstDayOfWeek.ordinal
    it.takeLast(n) + it.dropLast(n)
}

fun DayOfWeek.index(
    firstDayOfWeek: DayOfWeek = firstDayOfWeekBySystem()
) = when (firstDayOfWeek) {
    DayOfWeek.MONDAY -> isoDayNumber - 1
    DayOfWeek.SUNDAY -> {
        if (this == DayOfWeek.SUNDAY) 0
        else isoDayNumber
    }

    else -> error("Unexpected firstDayOfWeek: $firstDayOfWeek")
}


// E.g DayOfWeek.SATURDAY.daysUntil(DayOfWeek.TUESDAY) = 3
infix fun DayOfWeek.daysUntil(other: DayOfWeek): Int = (7 + (other.ordinal - ordinal)) % 7

operator fun DayOfWeek.plus(days:Int): DayOfWeek {
    var newOrdinal = ordinal + days
    while (newOrdinal < 0) {
        newOrdinal += 7
    }
    while (newOrdinal >= 7) {
        newOrdinal -= 7
    }
    return DayOfWeek.entries[newOrdinal]
}

operator fun DayOfWeek.minus(days:Int) =  this + (-days)